#include "Animation/GUIAnimationManager.h"
#include "Animation/GUIAnimationDefinition.h"
#include "Animation/GUIAnimation.h"
#include "GUILogger.h"
#include "GUIBase.h"
#include "XML/GUIXMLAnimationHandler.h"
#include "GUISystem.h"

namespace YGUI
{
    template<>
    AnimationManager* Singleton<AnimationManager>::m_singleton = 0;

    AnimationManager::AnimationManager(void)
    {
        allocInterpolators();
    }

    AnimationManager::~AnimationManager(void)
    {
        destroyAllAnimationDefinition();
        destroyAllInterpolators();
    }

    AnimationManager& AnimationManager::getSingleton()
    {
        static AnimationManager instance;
        return (*m_singleton);
    }

    AnimationManager* AnimationManager::getSingletonPtr(void)
    {
        if(!m_singleton)
            getSingleton();
        return m_singleton;
    }

    Interpolator* AnimationManager::getInterpolator(const String& type) const
    {
        InterpolatorMap::const_iterator it = m_interpolators.find(type);
        if(it == m_interpolators.end())
        {
            Logger::getSingleton().wprintf(L"AnimationManager::getInterpolator -- type of interpolator \"%s\""
                L" is not exists.\n", type.w_str());
            return 0;
        }
        return it->second;
    }

    void AnimationManager::addInterpolator(Interpolator* it)
    {
        if(!it)
        {
            Logger::getSingleton().wprintf(L"AnimationManager::addInterpolator -- parameter is invalid.\n");
            return;
        }
        if(m_interpolators.find(it->getType()) != m_interpolators.end())
        {
            Logger::getSingleton().wprintf(L"AnimationManager::addInterpolator -- interpolator with type"
                L" \"%s\" is aleardy exists.\n", it->getType().w_str());
            return;
        }
        m_interpolators.insert(std::make_pair(it->getType(), it));
    }

    void AnimationManager::removeInterpolator(Interpolator* it)
    {
        if(!it)
        {
            Logger::getSingleton().wprintf(L"AnimationManager::removeInterpolator -- parameter is invalid.\n");
            return;
        }
        InterpolatorMap::iterator i = m_interpolators.find(it->getType());
        if(i == m_interpolators.end())
        {
            Logger::getSingleton().wprintf(L"AnimationManager::removeInterpolator -- interpolator with type"
                L" \"%s\" is not exist.\n", it->getType().w_str());
            return;
        }
        m_interpolators.erase(i);
    }

    const String AnimationManager::generateUniqueAniDefName(void)
    {
        const wchar_t* const _prefix_name_fmt = L"__auto_ani_def_%u__";
        const size_t nBufferMax = 64;

        for(size_t i = m_aniDefinitions.size(); ; ++i)
        {
            wchar_t name[nBufferMax] = { 0 };
            _snwprintf_s(name, nBufferMax, nBufferMax - 1, _prefix_name_fmt, i);
            if(0 == getAnimationDefinition(name))
                return name;
        }
        return "";
    }

    AnimationDefinition* AnimationManager::createAnimationDefinition(const String& name)
    {
        if(name.empty()) return 0;
        AnimationDefinitionMap::iterator it = m_aniDefinitions.find(name);
        if(it != m_aniDefinitions.end())
            return it->second;
        AnimationDefinition* result = MEMCHECK_NEW AnimationDefinition(name);
        m_aniDefinitions.insert(std::make_pair(name, result));
        return result;
    }

    AnimationDefinition* AnimationManager::getAnimationDefinition(const String& name)
    {
        AnimationDefinitionMap::iterator it = m_aniDefinitions.find(name);
        if(it != m_aniDefinitions.end())
            return it->second;
        else
        {
            Logger::getSingleton().wprintf(L"AnimationManager::getAnimationDefinition -- animation template "
                L"with name \"%s\" is not exist.\n", name.w_str());
            return 0;
        }
    }

    void AnimationManager::destroyAnimationDefinition(const String& name)
    {
        AnimationDefinitionMap::iterator it = m_aniDefinitions.find(name);
        if(it == m_aniDefinitions.end())
            return;
        AnimationDefinition* val = it->second;
        destroyAnimations(val);
        m_aniDefinitions.erase(it);
        delete val;
    }

    void AnimationManager::destroyAnimationDefinition(AnimationDefinition* ptr)
    {
        if(!ptr) return;
        destroyAnimationDefinition(ptr->getName());
    }

    void AnimationManager::destroyAllAnimationDefinition(void)
    {
        while(!m_aniDefinitions.empty())
        {
            AnimationDefinitionMap::iterator it = m_aniDefinitions.begin();
            AnimationDefinition* val = it->second;
            m_aniDefinitions.erase(it);
            destroyAnimations(val);
            delete val;
        }
    }

    Animation* AnimationManager::generateAnimation(AnimationDefinition* def)
    {
        if(!def) { assert(false); return 0; }
        Animation* result = MEMCHECK_NEW Animation(def);
        m_animations.insert(std::make_pair(def, result));
        return result;
    }

    Animation* AnimationManager::generateAnimation(const String& name)
    {
        return generateAnimation(getAnimationDefinition(name));
    }

    void AnimationManager::destroyAnimations(AnimationDefinition* def)
    {
        AnimationMap::iterator it = m_animations.find(def);
        if(it == m_animations.end()) return;
        while(it->first == def)
        {
            delete it->second;
            it = m_animations.erase(it);
        }
    }

    void AnimationManager::removeAnimation(Animation* obj_ptr)
    {
        if(!obj_ptr) { assert(false); return; }
        AnimationMap::iterator it = m_animations.find(obj_ptr->getDefinition());
        for(; it != m_animations.end(); ++it)
        {
            if(it->second == obj_ptr)
            {
                m_animations.erase(it);
                return;
            }
        }
    }

    void AnimationManager::destroyAnimation(Animation* obj_ptr)
    {
        removeAnimation(obj_ptr);
        delete obj_ptr;
    }

    void AnimationManager::step(float delta)
    {
        for(AnimationMap::iterator it = m_animations.begin(); it != m_animations.end(); ++it)
            it->second->step(delta);
    }

    unsigned long AnimationManager::loadAnimationFromXML(const String& xml_filename)
    {
        AnimationXMLHandler handler;
        unsigned long err_code = System::getSingleton().getXMLParser()->parseXMLFile(handler, xml_filename);
        if(err_code)
        {
            Logger::getSingleton().wprintf(L"AnimationManager::loadAnimationFromXML -- Load animation xml "
                L"file failed with error code %u\n", err_code);
        }
        return err_code;
    }

    void AnimationManager::allocInterpolators(void)
    {
        addInterpolator(new FloatInterpolator);
        addInterpolator(new StringInterpolator);
    }

    void AnimationManager::destroyAllInterpolators(void)
    {
        InterpolatorMap::iterator it = m_interpolators.begin();
        for(; it != m_interpolators.end(); ++it)
        {
            delete it->second;
        }
        m_interpolators.clear();
    }
}